package it.webrules.deploymanager.core.dy;

import it.webrules.deploymanager.core.Function;
import it.webrules.deploymanager.core.OperationResult;
import it.webrules.deploymanager.core.config.Command;
import it.webrules.deploymanager.core.config.ConfigurationException;
import it.webrules.deploymanager.core.config.ConfigurationService;
import it.webrules.deploymanager.core.dy.build.BuilderConnection;
import it.webrules.deploymanager.core.dy.build.BuilderService;
import it.webrules.deploymanager.core.dy.build.CIException;
import it.webrules.deploymanager.core.dy.deploy.AvailableServerException;
import it.webrules.deploymanager.core.dy.deploy.DeployException;
import it.webrules.deploymanager.core.dy.deploy.DeployService;
import it.webrules.deploymanager.core.dy.repos.RepositoryConnection;
import it.webrules.deploymanager.core.dy.repos.RepositoryException;
import it.webrules.deploymanager.core.dy.repos.ReposytoryService;
import it.webrules.xsd.dmc.config.v1.ReleaseNumberingSource;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

public class DeployManagerWebapp implements Function {

	public boolean canManage(ConfigurationService configurationService) {
		return configurationService.getWebappConfig() != null;
	}

	public Object start(ConfigurationService configurationService) throws ConfigurationException, CIException, RepositoryException,
			AvailableServerException, DeployException {

		BuilderService buildService = new BuilderService(configurationService);
		ReposytoryService reposytoryService = new ReposytoryService(configurationService);
		DeployService deployService = new DeployService(configurationService);

		BuilderConnection buildConnection = buildService.getBuilderConnection();
		RepositoryConnection repositoryConnection = reposytoryService.getRepositoryConnection();

		Command command = configurationService.getCommand();
		switch (command) {

		case NextDefaultVersions:
			return getNextVersions(configurationService, buildConnection, repositoryConnection);

		case BuildAndDeploy:
			return buildAndDeploy(configurationService, deployService, buildConnection, repositoryConnection);

		case ListDeployableRelease:
			return listBuilds(buildConnection, repositoryConnection);

		case Deploy:
			return deploy(configurationService, deployService, buildConnection, repositoryConnection);

		default:
			return new OperationResult("Nothing to do, " + command + " is not for Dynamic Parts");
		}

	}

	private Versioning getNextVersions(ConfigurationService configurationService, BuilderConnection buildConnection,
			RepositoryConnection repositoryConnection) throws CIException, ConfigurationException, RepositoryException {

		Versioning versioning = new Versioning();
		versioning.setDevelop(configurationService.getDevelopmentVersion());
		versioning.setRelease(configurationService.getReleaseVersion());

		if (versioning.getDevelop() != null && !versioning.getDevelop().isEmpty() && versioning.getRelease() != null
				&& !versioning.getRelease().isEmpty())
			return versioning;

		if (configurationService.getWebappConfig().getConfig().getVersioningBy() == null
				|| configurationService.getWebappConfig().getConfig().getVersioningBy().equals(ReleaseNumberingSource.BUILD)) {

			if (buildConnection == null)
				throw new ConfigurationException("DevelopmentVersiong from build system, but build system not configured!");

			Versioning verFromBuild = buildConnection.getNextVersions();

			if (versioning.getDevelop() != null && !versioning.getDevelop().isEmpty())
				versioning.setDevelop(verFromBuild.getDevelop());

			if (versioning.getRelease() != null && !versioning.getRelease().isEmpty())
				versioning.setRelease(verFromBuild.getRelease());

		} else {

			if (repositoryConnection == null)
				throw new ConfigurationException("DevelopmentVersiong from repository system, but repository system not configured!");

			Versioning verFromRepos = repositoryConnection.getNextVersions();

			if (versioning.getDevelop() == null || versioning.getDevelop().isEmpty())
				versioning.setDevelop(verFromRepos.getDevelop());

			if (versioning.getRelease() == null || versioning.getRelease().isEmpty())
				versioning.setRelease(verFromRepos.getRelease());

		}

		return versioning;

	}

	private Object listBuilds(BuilderConnection buildConnection, RepositoryConnection repositoryConnection) throws RepositoryException,
			CIException {
		if (repositoryConnection != null)
			return repositoryConnection.getBuildHistory();
		if (buildConnection != null)
			return buildConnection.getBuildHistory();
		return new OperationResult(false, "No repository / build system configured!");
	}

	private OperationResult buildAndDeploy(ConfigurationService configurationService, DeployService deployService,
			BuilderConnection buildConnection, RepositoryConnection repositoryConnection) throws CIException, RepositoryException,
			ConfigurationException, AvailableServerException, DeployException {

		InputStream artifact;

		buildConnection.performBuild(getNextVersions(configurationService, buildConnection, repositoryConnection));

		if (repositoryConnection != null)
			artifact = repositoryConnection.getArtifact(configurationService.getBuildNumber());
		else
			artifact = buildConnection.getArtifact(configurationService.getBuildNumber());

		deployService.checkSystemReady();
		deployService.deploy(artifact);

		return new OperationResult();
	}

	private OperationResult deploy(ConfigurationService configurationService, DeployService deployService,
			BuilderConnection buildConnection, RepositoryConnection repositoryConnection) throws CIException, RepositoryException,
			ConfigurationException, AvailableServerException, DeployException {

		InputStream artifact;

		File artifactFile = configurationService.getArtifact();
		if (artifactFile == null) {

			if (repositoryConnection != null) {
				artifact = repositoryConnection.getArtifact(configurationService.getBuildNumber());
			} else if (buildConnection != null) {
				artifact = buildConnection.getArtifact(configurationService.getBuildNumber());
			} else {
				throw new ConfigurationException("Artifact file not selected!");
			}

		} else {

			try {
				artifact = new FileInputStream(artifactFile);
			} catch (FileNotFoundException e) {
				throw new ConfigurationException("Artifact file not found!", e);
			}

		}

		deployService.checkSystemReady();
		deployService.deploy(artifact);

		return new OperationResult();
	}

}
